package main

import (
	"context"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"protohook/hook_proxy"
)

//  @Descn: 监听/连接配置
type ROProxyConf struct {
	// 连接登录服的地址
	LoginIpAddr string `xml:"login_ip_addr,attr"`
	// 让客户端连的登录服的端口
	LoginListenPort int32 `xml:"login_listen_port,attr"`
	// 修改监听的gate的端口
	GateListenPort int32 `xml:"gate_listen_port,attr"`
}

// 用户自定义数据
type RORoleContext struct {
	// 登录账号
	openId string
	// 角色id
	roleId uint64
	// 角色名字
	userName string
	// 要连接的服务器地址
	connectServerAddress string
}
// 序列化成字符串,日志输出用
func (c *RORoleContext) String() string {
	return fmt.Sprintf("%s,%d,%s", c.openId, c.roleId, c.userName)
}

// @Desc RO用的hookevnet 实现接口HookEvent
type ROHookEvent struct {
	*hook_proxy.DefaultHookEvent
}

func (rohe *ROHookEvent) TryGetServerIpAddr(customCtx interface{}) (string, error) {
	if roleCtx, ok := customCtx.(*RORoleContext); ok  && len(roleCtx.connectServerAddress) > 0{
		return roleCtx.connectServerAddress, nil
	}
	return globalXmlConfig.ROHookProxyConf.LoginIpAddr, nil
}

func (rohe *ROHookEvent) OnMessage(buf []byte, customCtx interface{}, toServer bool) []byte {
	ctx, ok := customCtx.(*RORoleContext)
	if ok == false {
		return buf
	}
	head, err := RODecodeProtoHead(buf)
	if err != nil {
		return buf
	}
	from := "客户端"
	to := "服务器"
	if !toServer {
		from, to = to, from
	}
	msgType := "PTC"
	if (head.ProtoFlag & RPC_TYPE_FLAG) > 0 {
		msgType = "RPC"
	}
	if protoNode := GetProtoNode(head.ProtoId); protoNode != nil {
	    ignore := false
	    for _, v := range globalXmlConfig.IgnoreProtoList {
	    	if v == protoNode.Name {
	    		ignore = true
	    		break
			}
		}
		if !ignore {
			zap.S().Infof("[协议] %s 从[%s]到[%s]的[%s]协议[%d] Name[%s]",
				ctx.String(),
				from,
				to,
				msgType,
				head.ProtoId,
				protoNode.Name)
		}
	} else {
		zap.S().Infof("[协议] %s 从[%s]到[%s]的[%s]协议[%d], 名字和协议类型未知",
			ctx.String(),
			from,
			to,
			msgType,
			head.ProtoId)
	}
	parser := hook_proxy.TryGetProtocolParser(head.ProtoId)
	if parser != nil {
		msgBody := zlibUncompressMsgBody(head, buf[head.HeadLen:])
		if toServer {
			msgBody = (*parser).Client2Server(msgBody, customCtx)
		} else {
			msgBody = (*parser).Server2Client(msgBody, customCtx)
		}
		msgBody = zlibCompressMsgBody(head, msgBody)
		if finalMsg, err := ROEncode(head, msgBody); err == nil {
			return finalMsg
		}
	}
	return buf
}

func (rohe *ROHookEvent) CreateEmptyCustomContext() interface{} {
	return &RORoleContext{}
}

// 连接gate的event
type ROGateHookEvent struct {
	ROHookEvent
}

func (e *ROGateHookEvent) TryGetServerIpAddr(customCtx interface{}) (string, error) {
	if roleCtx, ok := customCtx.(*RORoleContext); ok  && len(roleCtx.connectServerAddress) > 0{
		return roleCtx.connectServerAddress, nil
	}
	return "", errors.New("Wait")
}


//  @Desc: 适用于RO项目的hook
//  @return bool 启动成功or失败
func ROHookProxyServe(ctx context.Context) bool {
	if !loadProtocolXML() {
		return false
	}
	zap.S().Info("[协议] 读取协议xml完成")
	registerSpecialProtocols()
	go hook_proxy.NewHookProxyAndServe(ctx, globalXmlConfig.ROHookProxyConf.GateListenPort, &ROGateHookEvent{})
	go hook_proxy.NewHookProxyAndServe(ctx, globalXmlConfig.ROHookProxyConf.LoginListenPort, &ROHookEvent{})
	return true
}
